package com.sghd.fight.module.game.service.skill;

import com.sghd.common.console.ConsoleBean;
import com.sghd.common.console.ConsoleCommand;
import com.sghd.common.utils.math.RandomUtils;
import com.sghd.fight.module.game.config.*;
import com.sghd.fight.module.game.service.skill.effect.Effect;
import com.sghd.fight.module.game.service.skill.effect.EffectType;
import com.sghd.pojo.fight.game.LevelVo;
import com.sghd.pojo.fight.game.RoomType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

@Component
@ConsoleBean
public class ConfigService extends Observable implements ApplicationContextAware {
    private final static Logger logger = LoggerFactory.getLogger(ConfigService.class);

    /** buff配置*/
    private Map<Integer, BuffConfig> buffs = new HashMap<>();
    /** 技能配置*/
    private Map<Integer, SkillConfig> skills = new HashMap<>();
    /** 关卡配置*/
    private Map<RoomType, RoomConfig> rooms = new HashMap<>();
    private Map<EffectType, Effect> effects = new HashMap<>();
    private Map<LevelId, LevelConfig> levels = new HashMap<>();
    /** 怪兽配置*/
    private Map<Integer, MonsterConfig> monsters = new HashMap<>();
    /** 五行属性配置*/
    private Map<ElementPk, ElementConfig> element2Attr = new HashMap<>();
    /** 公共配置*/
    private Map<ConfigNames, String> gameConfigs = new HashMap<>();
    /** 机器人配置*/
    private Map<Integer, RobotConfig> robotConfigs = new HashMap<>();
    private List<String> robotNames;
    @Autowired
    private ConfigManager configManager;

    @PostConstruct
    void init() throws Exception {
        this.addObserver(new Observer() {
            @Override
            public void update(Observable o, Object arg) {
                initConfig();
            }
        });
        reload();
        //读取机器人名字
        this.robotNames = new ArrayList<>(readFile(new ClassPathResource("name/RobotName.txt")));
    }

    /**
     * 初始化配置
     */
    private void initConfig() {
        List<BuffConfig> buffConfigs = configManager.getAll(BuffConfig.class);
        for (BuffConfig buffConfig : buffConfigs) {
            buffs.put(buffConfig.getId(), buffConfig.copy());
        }
        List<SkillConfig> skillConfigs = configManager.getAll(SkillConfig.class);
        for (SkillConfig skillConfig : skillConfigs) {
            skillConfig.setEffect(effects.get(skillConfig.getEffectType()));
            skills.put(skillConfig.getId(), skillConfig.copy());
        }
        List<LevelConfig> levelConfigs = configManager.getAll(LevelConfig.class);
        for (LevelConfig levelConfig : levelConfigs) {
            levels.put(levelConfig.getId(), levelConfig.copy());
        }
        List<MonsterConfig> monsterConfigs = configManager.getAll(MonsterConfig.class);
        for (MonsterConfig monsterConfig : monsterConfigs) {
            monsters.put(monsterConfig.getId(), monsterConfig.copy());
        }
        List<RoomConfig> roomConfigs = configManager.getAll(RoomConfig.class);
        for (RoomConfig roomConfig : roomConfigs) {
            rooms.put(roomConfig.getId(), roomConfig.copy());
        }
        List<ElementConfig> elementConfigs = configManager.getAll(ElementConfig.class);
        for (ElementConfig elementConfig : elementConfigs) {
            element2Attr.put(elementConfig.getId(), elementConfig.copy());
        }
        List<GameConfig> gameConfigs = configManager.getAll(GameConfig.class);
        for (GameConfig gameConfig : gameConfigs) {
            this.gameConfigs.put(gameConfig.getId(), gameConfig.getValue());
        }
        List<RobotConfig> robotConfigs = configManager.getAll(RobotConfig.class);
        for (RobotConfig robotConfig : robotConfigs) {
            this.robotConfigs.put(robotConfig.getId(), robotConfig.copy());
        }
    }

    public Set<String> readFile(Resource resource) throws Exception {
        Set<String> result = new HashSet<>();
        try (InputStreamReader reader = new InputStreamReader(resource.getInputStream());
             BufferedReader br = new BufferedReader(reader)
        ) {
            String line;
            while ((line = br.readLine()) != null) {
                result.add(line);
            }
        } catch (IOException e) {
            logger.error("初始化机器人配置发生未知错误！", e);
            throw e;
        }
        return result;
    }

    @ConsoleCommand(name = "reload", description = "重新载入数据库配置")
    public void reload() {
        this.setChanged();
        this.notifyObservers();
    }

    public SkillConfig getSkillConfig(int id) {
        return skills.get(id);
    }

    public BuffConfig getBuff(int buffId) {
        return buffs.get(buffId);
    }

    public RoomConfig getRoomConfig(RoomType type) {
        return rooms.get(type);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Effect> effectMap = applicationContext.getBeansOfType(Effect.class);
        for (Effect effect : effectMap.values()) {
            if (effects.containsKey(effect.getType())) {
                logger.error("配置项[{}]重复！", effect.getType());
                throw new RuntimeException();
            }
            effects.put(effect.getType(), effect);
        }
    }

    public LevelConfig getLevel(LevelVo levelVo) {
        LevelId levelId = new LevelId(levelVo.getBigLevelId(), levelVo.getLevelId());
        return levels.get(levelId);
    }

    public String getGConfig(ConfigNames name) {
        List<GameConfig> gameConfigs = configManager.getAll(GameConfig.class);
        for (GameConfig gameConfig : gameConfigs) {
            this.gameConfigs.put(gameConfig.getId(), gameConfig.getValue());
        }
        return this.gameConfigs.get(name);
    }

    public String getGameConfig(ConfigNames name) {
        return this.gameConfigs.get(name);
    }

    public MonsterConfig getMonsterConfig(int monsterId) {
        return monsters.get(monsterId);
    }

    public ElementConfig getAttr(ElementPk pk) {
        return element2Attr.get(pk);
    }

    public List<RobotConfig> getRobotConfigs() {
        return new ArrayList<>(robotConfigs.values());
    }

    public String getRobotName() {
        int random = RandomUtils.nextInt(robotNames.size());
        return robotNames.get(random);
    }
}
